package crmdna.client.teacher;

import static crmdna.common.OfyService.ofy;

import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.googlecode.objectify.Key;

import crmdna.client.group.Group;
import crmdna.client.sequence.Sequence;
import crmdna.client.sequence.Sequence.SequenceType;
import crmdna.client.user.User;
import crmdna.client.user.User.Action;
import crmdna.client.user.User.ResourceType;
import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;
import crmdna.common.Utils;
import crmdna.crmdna.Client;

public class Teacher {
	public static class TeacherProp {
		public long teacherId;
		public String email;
		public long groupId;				
	}
	
	public static TeacherProp create(String client, String email, long groupId, String login) {
		
		Client.ensureValidClient(client);
		User.ensureAccess(client, login, ResourceType.TEACHER, 0, Action.WRITE);
				
		Utils.ensureValidEmail(email);
		email = email.toLowerCase();
				
		List<Key<TeacherEntity>> keys = ofy(client).load()
				.type(TeacherEntity.class).filter("email", email).keys().list();
		
		if (keys.size() != 0)
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"There is already a teacher with name [" + email + "]");
			
		String key = getUniqueKey(client, email);
		long val = MemcacheServiceFactory.getMemcacheService()
				.increment(key, 1, (long)0);
		
		if (val != 1)
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"There is already a teacher with email [" + email + "]");
		
		TeacherEntity entity = new TeacherEntity();		
		entity.teacherId = Sequence.getNext(client, SequenceType.TEACHER);
		entity.email = email;
		entity.groupId = groupId;
		ofy(client).save().entity(entity).now();
		
		return entity.toProp();		
	}
	
	private static String getUniqueKey(String namespace, String name) {
		return namespace + "_" + SequenceType.TEACHER + "_" + name;
 	}
		
	public static TeacherEntity safeGet(String client, long teacherId) {
				
		Client.ensureValidClient(client);
		
		TeacherEntity entity = ofy(client).load().type(TeacherEntity.class).id(teacherId).get();
		if (null == entity)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"Teacher [" + teacherId + "] does not exist");
		
		return entity;		
	}		
	
	public static TeacherProp update(String client, long teacherId, String newEmail, Long newGroupId, 
			String login) {
						
		Client.ensureValidClient(client);
		User.ensureAccess(client, login, ResourceType.TEACHER, 0, Action.WRITE);
		
		if (newGroupId != null)
			Group.safeGet(client, newGroupId);
		
		TeacherEntity entity = safeGet(client, teacherId);
		
		if (newEmail != null) {
			Utils.ensureValidEmail(newEmail);
			newEmail = newEmail.toLowerCase();
							
			List<Key<TeacherEntity>> keys = ofy(client).load()
					.type(TeacherEntity.class).filter("email", newEmail).keys().list();		
			if (keys.size() != 0)
				throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
						"There is already a teacher with email [" + newEmail + "]");
					
			String key = getUniqueKey(client, newEmail);
			long val = MemcacheServiceFactory.getMemcacheService()
					.increment(key, 1, (long)0);
			
			if (val != 1)
				throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
						"There is already a teacher with name [" + newEmail + "]");
		}
		
		//ideally should be inside a transaction
		if (newEmail != null)
			entity.email = newEmail;
		if (newGroupId != null)
			entity.groupId = newGroupId;
		
		ofy(client).save().entity(entity).now();
		
		return entity.toProp();						
	}
	
	public static List<TeacherProp> getAll(String client) {
		
		Client.ensureValidClient(client);
		
		List<TeacherEntity> entities = ofy(client).load().type(TeacherEntity.class).order("email").list();
		
		List<TeacherProp> props = new ArrayList<>();
		for (TeacherEntity entity : entities) 
			props.add(entity.toProp());
		
		return props;				
	}
	
	public static void delete(String namespace, long teacherId, String login) {
						
		//TODO
		//need to check for all references before supporting delete
		throw new APIException(Status.ERROR_NOT_IMPLEMENTED, 
				"Deleting teacher entity is not yet implemented");				
	}
}
